package com.xliu.csopenproject.pim_server.image.meta.commonimagingimpl;

import com.xliu.csopenproject.pim_server.image.meta.ImageMetaData;
import com.xliu.csopenproject.pim_server.image.meta.ImageMetaWriter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.imaging.ImageWriteException;
import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.ImagingException;
import org.apache.commons.imaging.common.ImageMetadata;
import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;
import org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter;
import org.apache.commons.imaging.formats.tiff.TiffImageMetadata;
import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet;

import java.io.*;

@Slf4j
public class ImageMetaDataWriterImpl implements ImageMetaWriter {
    @Override
    public void write(ImageMetaData metaData, String srcPath, String dstPath) throws IOException {
        File jpegImageFile = new File(srcPath);
        File dst = new File(dstPath);

        try (FileOutputStream fos = new FileOutputStream(dst);
             OutputStream os = new BufferedOutputStream(fos)) {

            // TODO: test support image format
            TiffOutputSet outputSet = getTiffOutputSet(jpegImageFile);

            // if file does not contain any exif metadata, we create an empty set of exif metadata.
            // Otherwise, we keep all the other existing tags.
            if (null == outputSet) {
                outputSet = new TiffOutputSet();
            }

            writeMetadata(outputSet, metaData);

            new ExifRewriter().updateExifMetadataLossless(jpegImageFile, os, outputSet);
        } catch (ImagingException e) {
            log.error("write metadata [{}] from [{}] to [{}] error", metaData, srcPath, dstPath, e);
            throw new IOException("write metadata error", e);
        }
    }

    private static void writeMetadata(TiffOutputSet outputSet, ImageMetaData metaData) throws ImageWriteException {
        // TODO: support other metadata
//        final TiffOutputDirectory exifDirectory = outputSet.getOrCreateExifDirectory();
//        // make sure to remove old value if present (this method will not fail if the tag does not exist).
//        exifDirectory.removeField(ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
//        exifDirectory.add(ExifTagConstants.EXIF_TAG_APERTURE_VALUE, new RationalNumber(3, 10));

        outputSet.setGPSInDegrees(Double.parseDouble(metaData.getLongitude()), Double.parseDouble(metaData.getLatitude()));
    }

    private static TiffOutputSet getTiffOutputSet(File jpegImageFile) throws ImagingException, IOException {
        TiffOutputSet outputSet = null;

        // note that metadata might be null if no metadata is found.
        final ImageMetadata metadata = Imaging.getMetadata(jpegImageFile);
        final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
        if (null != jpegMetadata) {
            // note that exif might be null if no Exif metadata is found.
            final TiffImageMetadata exif = jpegMetadata.getExif();

            if (null != exif) {
                // TiffImageMetadata class is immutable (read-only).
                // TiffOutputSet class represents the Exif data to write.
                //
                // Usually, we want to update existing Exif metadata by
                // changing the values of a few fields, or adding a field.
                // In these cases, it is easiest to use getOutputSet() to
                // start with a "copy" of the fields read from the image.
                outputSet = exif.getOutputSet();
            }
        }
        return outputSet;
    }
}
